package com.woniuxy.lab.woniu_lab_boss.controller;



import cn.hutool.core.lang.Snowflake;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.woniuxy.lab.woniu_lab_boss.common.Result;

import com.woniuxy.lab.woniu_lab_boss.controller.form.ModifyRangeForm;
import com.woniuxy.lab.woniu_lab_boss.controller.form.UploadRangeForm;
import com.woniuxy.lab.woniu_lab_boss.exception.WebException;
import com.woniuxy.lab.woniu_lab_boss.exception.WebExceptionCode;
import com.woniuxy.lab.woniu_lab_boss.service.RangeService;

import com.woniuxy.lab.woniu_lab_boss.service.dto.RangeDto;
import com.woniuxy.lab.woniu_lab_boss.util.JwtUtil;
import com.woniuxy.lab.woniu_lab_boss.util.PathUtil;
import io.swagger.annotations.*;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.validator.constraints.Length;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.ResourceUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import java.io.*;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 靶场表 前端控制器
 * </p>
 *
 * @author Silas
 * @since 2023-03-15
 */
@RestController
@RequestMapping("/range")
@Slf4j
@Api(tags = "[I]靶场与实验相关接口")
@Validated
public class RangeController {

    @Value("${aliOSS.EndPoint}")
    private String endPoint;// 地域节点
    @Value("${aliOSS.BucketURL}")
    private String bucketURL;// bucket公网域名
    @Value("${aliOSS.BucketName}")
    private String bucketName;// bucket名称
    @Value("${aliOSS.AccessKeyID}")
    private String accessKeyID;
    @Value("${aliOSS.AccessKeySecret}")
    private String accessKeySecret;

    @Resource
    private RangeService rangeService;

    /**
     * 根据keyword查询靶场
     *
     * @param condition
     * @param page
     * @param size
     * @return
     */
    @ApiOperation("82 关键词搜索靶场")
    @GetMapping("/queryRange")
    public Result<IPage<RangeDto>> queryRange(
            @ApiParam(value = "关键词") @Length(max = 50,message = "关键字长度不能超过50")String condition,
            @ApiParam(value = "第几页") @Min(value = 1,message="页码必须大于1") Integer page,
            @ApiParam(value = "每页条数") @Min(value = 1,message="每页展示数必须大于1") @Max(value = 10,message = "每页展示数不能大于10") Integer size
    ) {
        log.info("查看靶场{}{}{}", condition, page, size);
        IPage<RangeDto> rangeDtoIPage = rangeService.queryRange(condition, page, size);
        return Result.success(200, "条件查询靶场成功", rangeDtoIPage);
    }

    /**
     * 查询所有靶场
     *
     * @param page
     * @param size
     * @return
     */
    @ApiOperation("81 查看所有靶场")
    @GetMapping("/queryAllRange")
    public Result<IPage<RangeDto>> queryAllRange(@ApiParam(value = "第几页") @Min(value = 1,message="页码必须大于1") Integer page,
                                                 @ApiParam(value = "每页条数") @Min(value = 1,message="每页展示数必须大于1") Integer size) {
        log.info("查看靶场{}{}", page, size);
        IPage<RangeDto> all = rangeService.findAll(page, size);
        return Result.success(200, "查询所有靶场成功", all);
    }

    /**
     * 根据type查询靶场
     *
     * @param condition
     * @param page
     * @param size
     * @return
     */
    @ApiOperation("83 按类别查询靶场")
    @GetMapping("/queryRangeByType")
    public Result<IPage<RangeDto>> queryRangeByType(
            @ApiParam(value = "类别[docker/war/php/file]")
            @Pattern(regexp = "^(docker|war|php|file)$", message = "类别必须为docker/war/php/file") String condition,
            @ApiParam(value = "第几页") @Min(value = 1,message="页码必须大于1") Integer page,
            @ApiParam(value = "每页条数") @Min(value = 1,message="每页展示数必须大于1") Integer size
    ) {
        log.info("查看靶场{}{}{}", condition, page, size);
        IPage<RangeDto> rangeDtoIPage = rangeService.queryByType(condition, page, size);
        return Result.success(200, "根据type查询靶场成功", rangeDtoIPage);
    }

    /**
     * 根据靶场是CTF还是EXPER查询靶场
     *
     * @param condition
     * @param page
     * @param size
     * @return
     */
    @ApiOperation("84 按CTF/安全实验查询靶场")
    @GetMapping("/queryRangeByWay")
    public Result<IPage<RangeDto>> queryRangeByWay(
            @ApiParam(value = "类型[ctf/exper]")
            @Pattern(regexp = "^(ctf|exper)$", message = "条件必须为ctf/exper")String condition,
            @ApiParam(value = "第几页")Integer page,
            @ApiParam(value = "每页条数")Integer size
    ) {
        log.info("查看靶场{}{}{}", condition, page, size);
        IPage<RangeDto> rangeDtoIPage = rangeService.queryByWay(condition, page, size);
        return Result.success(200, "根据类型查询靶场成功", rangeDtoIPage);
    }

    // 上传靶场
    @ApiOperation("65 上传靶场")
    @PostMapping("/uploadRange")
    public Result<Object> uploadRange(@RequestBody @Valid UploadRangeForm form) {
        log.info("上传靶场{}", form);
        rangeService.uploadRange(form);
        return Result.success(200, "SUCCESS", null);
    }

    /**
     * 下架靶场
     * @param rangeId 靶场ID
     * @return RangeDto
     */
    @ApiOperation("66 下架靶场")
    @PutMapping("/downRange")
    public Result<Object> downRange(@ApiParam(value = "靶场ID") @RequestParam @Min(value = 1,message="靶场ID必须大于0") Integer rangeId){
        log.info("开始下架靶场：{}",rangeId);
        rangeService.downRange(rangeId);
        return Result.success(200, "下架靶场成功",null);
    }

    /**
     * 查看我的靶场
     * @return List<RangeDto> 我的靶场集合
     */
    @ApiOperation("63 查看我的靶场（讲师）")
    @GetMapping("/findMyRange")
    public Result<IPage<RangeDto>> findMyRange(@RequestParam("page") @ApiParam(value = "页码")
                                               @Min(value = 1,message="页码必须大于1") Integer page,
                                               @RequestParam("size") @ApiParam(value = "每页展示数")
                                               @Min(value = 1,message="每页显示数必须大于1")
                                               @Max(value = 20,message="每页显示数不能超过20") Integer size) {
        log.info("讲师开始查询自己的靶场");
        IPage<RangeDto> rangeDtos= rangeService.findMyRange(page, size);
        return Result.success(200,"讲师：{}，开始查询自己的靶场成功",rangeDtos);
    }

    /**
     * 修改靶场信息
     * @param modifyRangeForm 修改靶场信息参数
     * @return RangeDto
     */
    @ApiOperation("67 修改靶场信息")
    @PutMapping("/modifyRange")
    public Result<RangeDto> modifyRange(@RequestBody @Valid ModifyRangeForm modifyRangeForm){
        log.info("开始修改靶场信息：{}",modifyRangeForm);
            RangeDto rangeDto= rangeService.modifyRange(modifyRangeForm);
            return Result.success(200,"修改靶场信息成功",rangeDto);
    }


    @ApiOperation("62 搜索我的靶场（讲师）")
    @GetMapping("searchMyRange")
    public Result<IPage<RangeDto>> searchMyRange(
            @ApiParam(value = "关键词")String keyword,
            @ApiParam(value = "第几页") @Min(value = 1,message="页码必须大于1")  Integer page,
            @ApiParam(value = "每页条数") @Min(value = 1,message="每页显示数必须大于1")  Integer size
    ) {
        log.info("查看靶场{}{}{}", keyword, page, size);

        IPage<RangeDto> rangeDto = rangeService.searchMyRange(page, size, keyword);
        return Result.success(200, "条件查询靶场成功", rangeDto);
    }

    // 条件筛选靶场（讲师）
    @ApiOperation("64 按类型筛选我的靶场")
    @GetMapping("/teacherRangeByType")
    public Result<IPage<RangeDto>> teacherRangeByType(
            @ApiParam(value = "类型[docker/war/php/file]")
                    @Pattern(regexp = "^(docker|war|php|file)$", message = "类型必须为docker/war/php/file") String type,
            @ApiParam(value = "第几页")Integer page,
            @ApiParam(value = "每页条数")Integer size
    ) {
        log.info("查看靶场{} {} {}", type, page, size);

        IPage<RangeDto> rangeDto = rangeService.getRangeByType(page, size, type);
        return Result.success(200, "根据type查询我的靶场成功", rangeDto);
    }

    /**
     * 文件上传
     * @param file 文件
     * @return url
     */
    @SneakyThrows
    @ApiOperation("87 上传文件")
    @PostMapping("/uploadFile")
    public Result<String> uploadFile(@ApiParam(value = "文件") @RequestPart(value = "file")
                                         @NotNull(message = "上传文件不能为空") MultipartFile file, HttpServletRequest request) {
        // 文件保存目录
        String fileSavePath = PathUtil.getFileSavePath();
        File dir = new File(fileSavePath);
        if (!dir.exists()) dir.mkdirs();

        // 以新文件存储
        String fileName = new Date().getTime() + "_" + file.getOriginalFilename();
        File newFile = new File(fileSavePath + fileName);

        // 复制文件
        String url = "";
        try {
            file.transferTo(newFile);
            url = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + "/files/" + fileName;
        } catch (IOException e) {
            throw new WebException(WebExceptionCode.FILE_UPLOAD_FAILED);
        }

        // http://192.168.120.10:8090/files/1679474873802@接口样例.docx
        return Result.success(200, "SUCCESS", url);

    }

    // 图片上传
    @ApiOperation("88 上传封面")
    @PostMapping("/uploadPic")
    public Result<String> uploadPic(@ApiParam(value = "封面文件") @RequestPart(value = "file")
                                        @NotNull(message = "上传文件不能为空")MultipartFile file) throws IOException {

        log.info("开始文件上传：{}", file);
        String orderNo = new Snowflake(1, 1).nextIdStr();// 雪花算法生成随机字符串
        String rawName = file.getOriginalFilename();// 获取原始文件名称
        String fileName = orderNo + rawName;
        OSS ossClient = new OSSClientBuilder().build(endPoint, accessKeyID, accessKeySecret);// 创建OSS连接服务对象
        ossClient.putObject(bucketName, fileName, file.getInputStream());// 向bucketName这个桶容器存入名为rawName的文件（流形式上传）
        String url = bucketURL + fileName;// 文件的url
        return Result.success(200, "SUCCESS", url);
    }

}

